#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <mysql.h>
#include <glib.h>

MYSQL *mysql;
MYSQL_RES *results;
MYSQL_ROW record;

static char *server_options[] = {
    "mysql_test",
    "--defaults-file=/tmp/mysql_test/my.cnf",
    "--datadir=/tmp/mysql_test/data",
    NULL
};

#define SERVER_OPTION_NUM ((sizeof(server_options) / sizeof(char *)) - 1)

static char *server_groups[] = {
    "embedded",
    "server",
    NULL
};

static const char hex_digits[] = "0123456789abcdef";
static void digest_to_string(char *digest, gsize digest_len, char *buf)
{
    int i;
    for (i = 0; i < digest_len; ++i) {
        uint8_t byte = digest[i];
        buf[i * 2] = hex_digits[byte >> 4];
        buf[i * 2 + 1] = hex_digits[byte & 0xf];
    }
    buf[digest_len * 2] = '\0';
}

static void
get_checksum(void *buf, size_t size, guint8 *result, gsize *len)
{
    GChecksum *cs = g_checksum_new(G_CHECKSUM_SHA1);
    g_checksum_update(cs, buf, size);
    g_checksum_get_digest(cs, result, len);
    g_checksum_free(cs);
}

int main(void)
{
    mysql_library_init(SERVER_OPTION_NUM, server_options, server_groups);
    mysql = mysql_init(NULL);
    mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "embedded");
    mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);

    if (!mysql_real_connect(mysql, NULL,NULL,NULL, NULL, 0, NULL,0)) {
        fprintf(stderr, "Failed to connect to database. Error: %s\n",
                mysql_error(mysql));
        goto err;
    }
    if (mysql_query(mysql, "CREATE DATABASE IF NOT EXISTS database1")) {
        fprintf(stderr, "Failed to create database. Error: %s\n",
                mysql_error(mysql));
        goto err;
    }
    if (mysql_select_db(mysql, "database1")) {
        fprintf(stderr, "Failed to select database. Error: %s\n",
                mysql_error(mysql));
        goto err;
    }
    if (mysql_query(mysql, "CREATE TABLE IF NOT EXISTS table1 ("
            "inode INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY, "
            "parent INTEGER UNSIGNED, "
            "name CHAR(255), "
            "timestamp BIGINT, "
            "checksum BINARY(20), "
            "INDEX (parent))")) {
        fprintf(stderr, "Failed to create table. Error: %s\n",
                mysql_error(mysql));
        goto err;
    }

    if (mysql_query(mysql, "INSERT IGNORE INTO table1 VALUES ("
            "1, NULL, 'home_path', 0, NULL)")) {
        fprintf(stderr, "Failed to create first row. Error: %s\n",
                mysql_error(mysql));
        goto err;
    }

    GString *sql = g_string_sized_new(1024);
    srand(time(NULL));
    int r = rand();
    char buf[20];
    char buf2[41];
    gsize len = sizeof (buf);
    get_checksum(&r, sizeof (r), (guint8 *) buf, &len);
    g_assert(len == 20);
    digest_to_string(buf, 20, buf2);
    gchar* sha1sum = g_compute_checksum_for_data(G_CHECKSUM_SHA1,
            (const guchar *) &r, sizeof (r));
    g_message("buf2: %s,len: %lu", buf2, strlen(buf2));
    g_message("sha1sum: %s, len: %lu", sha1sum, strlen(sha1sum));
    g_string_printf(sql, "INSERT INTO table1 VALUES ("
            "DEFAULT, 1, 'test', %ld, x'%s')",
            time(NULL), buf2);

    //g_message("sql = %s", sql->str);
    if (mysql_query(mysql, sql->str)) {
        fprintf(stderr, "Failed to insert. Error: %s\n", mysql_error(mysql));
        goto err;
    }

    g_message("inserted inode: %d", (int) mysql_insert_id(mysql));

    mysql_query(mysql, "SELECT * FROM table1");

    results = mysql_store_result(mysql);

    while((record = mysql_fetch_row(results))) {
        if (record[4] == NULL) {
            printf("%s - %s - %s - %s - %s\n",
                    record[0], record[1], record[2], record[3], record[4]);
        } else {
            char buf[41];
            digest_to_string(record[4], 20, buf);
            printf("%s - %s - %s - %s - x'%s'\n",
                    record[0], record[1], record[2], record[3], buf);
        }
    }

    mysql_free_result(results);
err:
    mysql_close(mysql);
    mysql_library_end();

    return 0;
}
